package world.snowcrystal.nova.scoring;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.springframework.stereotype.Component;
import world.snowcrystal.nova.model.dto.question.QuestionDto;
import world.snowcrystal.nova.model.entity.App;
import world.snowcrystal.nova.model.entity.Question;
import world.snowcrystal.nova.model.entity.ScoringResult;
import world.snowcrystal.nova.model.entity.UserAnswer;
import world.snowcrystal.nova.model.enums.AppScoringStrategyEnum;
import world.snowcrystal.nova.model.enums.AppScoringTypeEnum;
import world.snowcrystal.nova.model.vo.QuestionVO;
import world.snowcrystal.nova.service.QuestionService;
import world.snowcrystal.nova.service.ScoringResultService;

import javax.annotation.Resource;
import java.util.List;
import java.util.Optional;


/**
 * <p>将数字(通常称为分数)赋值给一个人的特定属性或特征；用数字来描述这个人拥有特征的程度；比如 80 表示良好 60 表示及格
 * 【当一组数字被分配给每一组物体，无论是人还是商品，按照公认的规则或标准，并用标准的文字、单位和符号描述，
 * 以表示该物体的状态，它被称为作为测量】</p>
 * 测量从物理学科的角度来说是指确定某个物理对象的属性或尺寸的过程。当我们测量时，我们通常使用一些标准仪器
 * 来确定某物到底有多大、多高、多重、多宽、多热、多冷、多快或多直。标准仪器是指尺子、刻度、温度计、压力表
 * 等物理仪器。我们通过测量来获取信息。这些信息取决于我们使用的仪器的准确性，以及我们使用它们的技巧。我们
 * 用平方米来测量教室的大小，我们用温度计来测量房间的温度。
 * 在这里，我们没有评估任何东西;我们只是收集与某些既定规则或标准相关的信息。
 *
 * @see <a href="https://zhuanlan.zhihu.com/p/454727321">特征评鉴</a>
 */
@Component
public class CustomMeasurementScoringStrategy implements ScoringStrategy {

    @Resource
    private QuestionService questionService;


    @Resource
    private ScoringResultService scoringResultService;


    @Override
    public UserAnswer score(List<String> choices, App app) throws Exception {

        // 根据 appId 获取题目和结果信息(按照 scoringRange 降序排序)
        Long appId = app.getId();

        // 根据 App id 获取 题目以及评分信息
        final Question question = questionService.getOne(
                Wrappers.lambdaQuery(Question.class)
                        .eq(Question::getAppId, appId)
        );
        final List<ScoringResult> scoringResults = scoringResultService.list(Wrappers.lambdaQuery(ScoringResult.class)
                .eq(ScoringResult::getAppId, appId)
                .orderByDesc(ScoringResult::getResultScoreRange)
        );

        QuestionVO questionVO = QuestionVO.objToVo(question);
        final List<QuestionDto> questionContent = questionVO.getQuestionContent();

        int score = 0;
        // 根据用户选择和结果信息，计算得分
        for (QuestionDto questionDto : questionContent) {
            // 遍历答案列表
            for (String choice : choices) {
                // 遍历评分结果列表
                for (QuestionDto.Option option : questionDto.getOptions()) {
                    if (!option.getKey().equals(choice)) {
                        continue;
                    }
                    score += Optional.ofNullable(option.getScore()).orElse(0);
                }
            }
        }

        // 遍历每个 Range
        ScoringResult result = null;
        for (ScoringResult scoringResult : scoringResults) {
            if (score >= scoringResult.getResultScoreRange())
            {
                result =  scoringResult;
                break;
            }
        }
        assert result != null;
        return UserAnswer.builder()
                .resultScore(score)
                .appId(appId)
                .appType(app.getAppType())
                .scoringStrategy(app.getScoringStrategy())
                .resultDesc(result.getResultDesc())
                .resultPicture(result.getResultPicture())
                .resultName(result.getResultName())
                .choices(JSONUtil.toJsonStr(choices))
                .build();
    }

    @Override
    public boolean isSupport(App app) {
        final Integer appType = app.getAppType();
        final Integer scoringStrategy = app.getScoringStrategy();
        if(ObjectUtil.isNull(scoringStrategy) && ObjectUtil.isNull(appType)){
            return false;
        }
        return appType.equals(AppScoringTypeEnum.MEASUREMENT.getValue())
                && scoringStrategy.equals(AppScoringStrategyEnum.CUSTOM.getValue());
    }
}

